package com.bw.auth.controller;


import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTHeader;
import cn.hutool.jwt.signers.JWTSignerUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;


import com.bw.aop.annotation.PhoneValidator;
import com.bw.aop.domain.ResultDTO;
import com.bw.aop.service.ResultService;
import com.bw.auth.config.OnlineUserStatistics;
import com.bw.auth.domain.*;
import com.bw.auth.service.*;


import com.bw.auth.utils.JackMaIpUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.core.domain.R;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionListener;
import javax.validation.Valid;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;


@RestController
@RequestMapping("/user")
@Validated//非空校验注解
public class AuthController implements HttpSessionListener {
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private OnlineUserStatistics onlineUserStatistics;
    @Autowired
    private SysUserRoleService userRoleService;
    @Autowired
    private SysUserDeptService userDeptService;
    @Autowired
    private SysUserPostService userPostService;
    @Autowired
    private SysRoleService roleService;
    @Autowired
    private ResultService resultService;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private SysDeptService deptService;
    public static List<String> list = new ArrayList<String>();



    @RequestMapping("/login")
    public R login(@RequestBody SysUser sysUser,HttpSession session){
        SysUser one = sysUserService.getUser(sysUser);
        if (one == null){
            return R.fail("用户不存在");
        }
        String password = DigestUtil.md5Hex(one.getSalt()+sysUser.getPassword());
        if (!StrUtil.equalsIgnoreCase(password,one.getPassword())){
            return R.fail("密码错误");
        }
        if (redisTemplate.hasKey("login"+one.getId())){
            return R.fail("该用户已登录");
        }
        String loginToken = JWT.create()
                .setPayload("id", one.getId())
                .setPayload("name", one.getUname())
                .setPayload("role", one.getName())
                .setSigner(JWTSignerUtil.none())
                .sign();
        onlineUserStatistics.userLoggedIn(one.getId()+"");//计算在线人数
        redisTemplate.opsForValue().set("login"+one.getId(),one,2,TimeUnit.HOURS);//防止重复登录
        redisTemplate.opsForValue().set("uid",one.getId());//防止重复登录
        Map<String,Object> map = new HashMap<>();
        map.put("token",loginToken);
        map.put("user",one);
        return R.ok(map);
    }


    /**
     * 注册
     * @param sysUser
     * @return
     */
    @RequestMapping("/register")
    public R register(@RequestBody @Valid SysUser sysUser) {

        //表单防重复提交
        String remoteAddr = request.getRemoteAddr();
        Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(remoteAddr + sysUser, sysUser.toString(), 1, TimeUnit.MINUTES);
        if (aBoolean) {
            //查询数据库
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.eq("uname", sysUser.getUname());
            queryWrapper.or();
            queryWrapper.eq("tel", sysUser.getTel());
            SysUser one = sysUserService.getOne(queryWrapper);
            if (one != null) {
                return R.fail("用户已存在");
            }
            //加盐加密
            String salt = RandomUtil.randomNumbers(4);
            String password = DigestUtil.md5Hex(salt + sysUser.getPassword());
            sysUser.setSalt(salt);
            sysUser.setPassword(password);
            sysUser.setStatus("普通");
            sysUser.setCreateDate(new Date());
            sysUserService.save(sysUser);
            //添加默认角色
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setUserId(sysUser.getId());
            sysUserRole.setRoleId(2);
            userRoleService.save(sysUserRole);

            return R.ok("注册成功");
        } else {
            return R.fail("表单已提交，无需重复发送");
        }
    }

    /**
     * 用户注销
     * @param id
     * @return
     */
        @RequestMapping("/deleteUser1")
    public Boolean deleteUser(@RequestBody Integer id){
        QueryWrapper queryWrapper =new QueryWrapper();
        queryWrapper.eq("id",id);
        SysUser one = sysUserService.getOne(queryWrapper);
        if (one == null){
            return false;
        }
        sysUserService.removeById(one);
        return true;
    }

    /**
     * 查询用户
     */
    @RequestMapping("/sysUser")
    public R sysUserlist(@RequestBody SysUser sysUser, Integer current,Integer size){
        PageHelper.startPage(current,size);
        List<PoSysUser> userlist = sysUserService.getUserlist(sysUser);
        return R.ok(new PageInfo<>(userlist));
    }

    /**
     * 添加用户
     * @param sysUser
     * @param rid
     * @param did
     * @return
     */
    @PhoneValidator("普通人")
    @RequestMapping("/addsysUser")
    public R addsysUser(@RequestBody SysUser sysUser,Integer rid,Integer did){
        boolean b = sysUserService.addsysUser(sysUser, rid, did);
        return R.ok();
    }



    /**
     * 用户删除
     * @param id
     * @return
     */
    @RequestMapping("/deleteUser")
    @Transactional
    public R deleteUser(String id){
        QueryWrapper queryWrapper =new QueryWrapper();
        queryWrapper.eq("id",id);
        SysUser one = sysUserService.getOne(queryWrapper);
        System.err.println(one);
        if (one == null){
            return R.fail();
        }
        boolean b = sysUserService.removeById(one);
        boolean remove = userPostService.remove(Wrappers.<SysUserPost>query().lambda().eq(SysUserPost::getUserId, id));
        boolean remove1 = userRoleService.remove(Wrappers.<SysUserRole>query().lambda().eq(SysUserRole::getUserId, id));
        boolean remove2 = userDeptService.remove(Wrappers.<SysUserDept>query().lambda().eq(SysUserDept::getUserId, id));
        System.err.println(true&b&remove1&remove2&remove);
        return true&b&remove1&remove2&remove?R.ok():R.fail();
    }

    /**
     * 用户修改
     * @param user
     * @param rolename
     * @param deptname
     * @return
     */
    @RequestMapping("modifyUsers")
    @Transactional
    public Boolean modifyUsers(@RequestBody SysUser user,String rolename,String deptname){
        if (user!=null && !rolename.isEmpty() && !deptname.isEmpty()){
            System.err.println(user);
            boolean b = sysUserService.updateById(user);
            LambdaQueryWrapper<SysRole> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(SysRole::getName,rolename);
            SysRole sysRole = roleService.getOne(wrapper);
            LambdaQueryWrapper<SysDept> deptwrapper = new LambdaQueryWrapper<>();
            deptwrapper.eq(SysDept::getName,deptname);
            SysDept sysDept = deptService.getOne(deptwrapper);
            boolean remove1 = userRoleService.remove(Wrappers.<SysUserRole>query().lambda().eq(SysUserRole::getUserId, user.getId()));
            boolean save = userRoleService.save(new SysUserRole(null, sysRole.getId(), user.getId()));
            boolean remove2 = userDeptService.remove(Wrappers.<SysUserDept>query().lambda().eq(SysUserDept::getUserId, user.getId()));
            boolean save1 = userDeptService.save(new SysUserDept(null,user.getId(),sysDept.getId()));
            return true;

        }
        return false;
    }

    /**
     * 在线用户列表
     */
    @RequestMapping("/useronline")
    public R useronline() throws IOException, ClassNotFoundException {
      Set<String>  keys =redisTemplate.keys("userolines:*");
        System.out.println("---------简直"+keys);
        // 2. 创建一个用于存储结果的集合
        List<SysUserOnline> sysUserOnlines = new ArrayList<>();
        // 3. 遍历键并获取集合中的值  
        for (String key : keys) {
            String jsonString = (String) redisTemplate.opsForValue().get(key);
            if(jsonString!=null){
                SysUserOnline userOnline = JSON.parseObject(jsonString, SysUserOnline.class);
                sysUserOnlines.add(userOnline);
            }
        }
        System.out.println("---------------在线用户"+sysUserOnlines);

        return R.ok(sysUserOnlines);
    }
    /**
     * 强退
     */
//    @PhoneValidator("管理员")
    @RequestMapping("/exit")
    public R userexit(Integer id){
        redisTemplate.delete("userolines:"+id);
        redisTemplate.delete("login"+id);
        redisTemplate.opsForSet().remove("onlineUsers", id+"");
        return R.ok();
    }
    /**
     * 判断是否在线
     */
    @RequestMapping("/getonline")
    public R getonline(String token){
        JWT of = JWT.of(token);
        Integer id = (Integer) of.getPayload("id");
        Boolean aBoolean = redisTemplate.hasKey("userolines:" + id);
        if(aBoolean){
            return R.ok();
        }
        return R.fail("已被推出");
    }
    /**
     * 过期自动退
     */
    @RequestMapping("/ifexprie")
    public R ifexprie(String token){
        JWT of = JWT.of(token);
        Integer id = (Integer) of.getPayload("id");
        Set<String> sysonline = redisTemplate.keys("userolines:" + id + "*");
        for (String key : sysonline) {
            String jsonString = (String) redisTemplate.opsForValue().get(key);
            SysUserOnline userOnline = JSON.parseObject(jsonString, SysUserOnline.class);
            Date createDate = userOnline.getCreateDate();
            Date date = new Date();
            int compare = DateUtil.compare(date, createDate);
            long between = DateUtil.between(date, createDate, DateUnit.MINUTE);
            if(compare>0&&between>1){
                System.out.println("bjcbvvf"+sysonline);
                redisTemplate.delete("userolines:"+id);
                redisTemplate.delete("login"+id);
                redisTemplate.opsForSet().remove("onlineUsers",id+"");
                return R.fail("过期自动退");
            }
        }
        return R.ok();
    }
    /**
     * 人数统计返回接口
     * @return
     */
    @RequestMapping("/count")
    public R count(){
        long onlineUserCount = onlineUserStatistics.getOnlineUserCount();
        return R.ok(onlineUserCount) ;
    }

    /**
     * 全局异常处理注解，在spring启动后，会自动扫描当前层的异常
     */
    @RestControllerAdvice
    public class ValidationExceptionHandler {

        @ExceptionHandler(MethodArgumentNotValidException.class)
        public R handleValidationException(MethodArgumentNotValidException e) {
            List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
            StringBuilder errorMessage = new StringBuilder();
            for (FieldError error : fieldErrors) {
                errorMessage.append(error.getDefaultMessage()).append("; ");
            }
            return R.fail(errorMessage.toString());
        }

    }

    /**
     * 退出登录
     * @param token
     * @return
     */
    @RequestMapping("/outLogin")
    public R outLogin(String token){
        JWT of = JWT.of(token);
        of.getHeader(JWTHeader.TYPE);
        Integer id = (Integer) of.getPayload("id");
        onlineUserStatistics.userLoggedOut(id+"");
        redisTemplate.delete("login"+id);
        redisTemplate.opsForSet().remove("onlineUsers",id+"");
        redisTemplate.delete("userolines:"+id);
        return R.ok("退出成功");
    }
    /**
     * 个人设置查看用户方法
     * 查看用户详情方法
     * @param token
     * @return
     */

    @RequestMapping("/getDetails")
    public R getDetails(String token){
        JWT of = JWT.of(token);
        of.getHeader(JWTHeader.TYPE);
        Integer id = (Integer) of.getPayload("id");
        SysUser byId = sysUserService.getById(id);
        SysUser user = sysUserService.getUser(byId);

        //获取ip属地
        String ipAddress = JackMaIpUtils.getIpAddress();
        user.setIp(ipAddress);
        System.err.println(user);
        return R.ok(user);
    }

    /**
     * 定时任务：每周的周五下午18点，发送邮件给管理员
     */
    @Scheduled(cron = "0 33 17 * * ?")
    @RequestMapping("/nihao")
    public void alRegularTime() throws IOException {
        // 假设我们有一个服务来存储或更新结果
        String msg="开始定期盘点";
        ResultDTO resultDTO = new ResultDTO(true, msg);
        resultService.daddResultDTO(resultDTO);
        //发送mq
        Message<Integer> messageBuilder =
                MessageBuilder.withPayload(1).build();
        rocketMQTemplate.asyncSend("demo6", messageBuilder, new SendCallback()
        {
            @Override
            public void onSuccess(SendResult sendResult) {
                System.out.println("发送成功---");
            }
            @Override
            public void onException(Throwable throwable) {
                System.out.println("发送失败---");
            }
        });
    }
    @RequestMapping("/dlatest")
    public R dgetLatestResult() {
        ResultDTO resultDTO = resultService.dgetLatestResult();
        return R.ok(resultDTO);
    }

    @RequestMapping("/null")
    public R hetnul(){
        ResultDTO resultDTO1 = new ResultDTO();
        resultService.daddResultDTO(resultDTO1);
        resultService.addResultDTO(resultDTO1);
        return R.ok();
    }

}
